在Nest.js的文档中看到了有集成GraphQL的指导,所以在本地尝试下先用Koa写出一个DEMO,之后再去与Nest.js集成起来。
先写出数据库模型(这个文件是之前就存在的,没有做更改,将文件名改成了models.ts):
/**
* Created by w on 2018/4/13.
*/
const mongoose = require('mongoose');
mongoose.Promise = global.Promise;
mongoose.connect('mongodb://localhost/ticket', {
server: {
socketOptions: {
keepAlive: 1
}
}
});
const models = {
users: {
username: {
type: String,
required: true
},
password: {
type: String,
required: true
},
description: {
type: String
},
createTime: {
type: Date,
default: new Date()
}
},
tickets: {
name: {
type: String,
required: true
},
price: {
type: Number,
requred: true
},
holdTime: { //举办时间
type: Date,
required: true
},
count: { //剩余数量
type: String,
required: true
},
place:{
type: String,
required: true
},
img: {
type: String
},
description: {
type: String
},
publicTime: {
type: Date,
default: new Date()
},
}
};
for (let m in models) {
mongoose.model(m, mongoose.Schema(models[m]));
}
module.exports = {
getModules: (name) => {
return mongoose.model(name);
}
};
之后编写各自模型的GraphQL查询文件(user.ts)):
// @ts-ignore
const {
//@ts-ignore
graphql, GraphQLSchema, GraphQLObjectType, GraphQLString, GraphQLID, GraphQLList, GraphQLNonNull, GraphQLInt, isOutputType,
} = require('graphql');
// @ts-ignore
const User = require('../db/model').getModules('users');
const userType = new GraphQLObjectType({
name: 'User',
fields: {
username: {
type: GraphQLString,
},
password: {
type: GraphQLString,
},
description: {
type: GraphQLString,
},
createTime: {
type: GraphQLString,
}
}
});
module.exports = {
query: {
type: new GraphQLList(userType),
args: {
username: {
username: 'username',
type: GraphQLNonNull(GraphQLString)
}
},
resolve(root, params, options) {
if (params.username === '$all') {
return User.find().exec()
}
return User.find({ username: params.username }).exec();
}
},
mutate: {
type: new GraphQLList(userType),
args: {
operate: {
name: 'operate',
type: GraphQLString
},
username: {
name: 'username',
type: GraphQLNonNull(GraphQLString)
},
possword: {
name: 'price',
type: GraphQLNonNull(GraphQLString)
},
createTime: {
name: 'createTime',
type: GraphQLString,
},
description: {
name: 'description',
type: GraphQLString
}
},
resolve: async (root, params, options) => {
try {
if (params.operate === '$delete') {
await User.delete({username: params.username});
return User.find().exec()
}
if (params.operate === '$update') {
await User.update({username: params.username});
return User.find({ username: params.username }).exec()
}
let user = new User({
username: params.username,
password: params.password,
description: params.description,
createTime: params.createTime
});
await user.save();
return user.find({ username: params.username }).exec()
} catch (e) {
console.error("Error while save data: ", e);
}
}
}
}
ticket.ts:
// @ts-ignore
const {
// @ts-ignore
graphql, GraphQLSchema, GraphQLObjectType, GraphQLString, GraphQLID, GraphQLList, GraphQLNonNull, GraphQLInt, isOutputType,
} = require('graphql');
// @ts-ignore
const Ticket = require('../db/model').getModules('tickets');
const ticketType = new GraphQLObjectType({
name: 'Ticket',
fields: {
name: {
type: GraphQLString
},
price: {
type: GraphQLInt
},
holdTime: {
type: GraphQLString
},
count: {
type: GraphQLInt
},
place: {
type: GraphQLString
},
img: {
type: GraphQLString
},
description: {
type: GraphQLString
},
publicTime: {
type: GraphQLString
}
}
});
module.exports = {
query: {
type: new GraphQLList(ticketType),
args: {
name: {
name: 'name',
type: GraphQLNonNull(GraphQLString)
}
},
resolve(root, params, options) {
if (params.name === '$all') {
return Ticket.find().exec()
}
return Ticket.find({ name: params.name }).exec();
}
},
mutate: {
type: new GraphQLList(ticketType),
args: {
operate: {
name: 'operate',
type: GraphQLString
},
name: {
name: 'name',
type: GraphQLNonNull(GraphQLString)
},
price: {
name: 'price',
type: GraphQLInt
},
holdTime: {
name: 'holdTime',
type: GraphQLNonNull(GraphQLString)
},
count: {
name: 'count',
type: GraphQLNonNull(GraphQLInt)
},
place: {
name: 'place',
type: GraphQLNonNull(GraphQLString)
},
img: {
name: 'img',
type: GraphQLString
},
description: {
name: 'description',
type: GraphQLString
},
publicTime: {
name: 'publicTime',
type: GraphQLString
}
},
resolve: async (root, params, options) => {
try {
if (params.operate === '$delete') {
await Ticket.findOneAndRemove({ name: params.name });
return Ticket.find().exec();
}
if (params.operate === '$update') {
await Ticket.findByIdAndUpdate({ name: params.name }, {
name: params.name,
price: params.price,
holdTime: params.holdTime,
count: params.count,
place: params.place,
img: params.img,
description: params.description,
publicTime: params.publicTime
});
return Ticket.find().exec();
}
let ticket = new Ticket({
name: params.name,
price: params.price,
holdTime: params.holdTime,
count: params.count,
place: params.place,
img: params.img,
description: params.description,
publicTime: params.publicTime
});
await ticket.save();
return Ticket.find({ name: params.name }).exec()
} catch (e) {
console.error("Error while save data: ", e);
}
}
}
}
接下来编写用于查询或修改数据的Schema.ts:
const {
//@ts-ignore
GraphQLSchema, GraphQLObjectType,
} = require('graphql');
//@ts-ignore
const Ticket = require('./ticket');
//@ts-ignore
const User = require('./user');
module.exports = new GraphQLSchema({
query: new GraphQLObjectType({
name: 'Queries',
fields: {
Ticket: Ticket.query,
User: User.query,
}
}),
mutation: new GraphQLObjectType({
name: 'Mutations',
fields: {
Ticket: Ticket.mutate,
User: User.mutate,
}
})
})
编写服务端(server.ts):
const Koa = require('koa');
const app = new Koa();
const koaBody = require('koa-body');
const CombileRouter = require('./combineRouter');
app
.use(koaBody({
multipart: true,
formidable: {
keepExtensions: true,
},
}))
.use(CombileRouter.routes())
.use(CombileRouter.routes());
app.listen(5000, () => {
console.log('App running~');
})
定义ticket路由的ticket.router.ts:
const KoaRouter = require('koa-router');
const ticketRouter = new KoaRouter();
// @ts-ignore
const { graphqlKoa, graphiqlKoa } = require('graphql-server-koa');
// @ts-ignore
const Ticket = require('../db/model').getModules('tickets');
const ticketSchema = require('../graphql/schema');
ticketRouter.get('/ticket/all', async (ctx) => {
try {
let result = await Ticket.find({});
ctx.body = { data: Object.assign({}, result), code: '0' };
} catch (e) {
console.error("Getting all ticket error: ", e);
}
});
ticketRouter.post('/graphql', async (ctx, next) => {
console.log('graphql', ctx.request.body);
await graphqlKoa({schema: ticketSchema})(ctx, next)
})
.get('/graphql', async (ctx, next) => {
await graphqlKoa({schema: ticketSchema})(ctx, next)
})
.get('/graphiql', async (ctx, next) => {
await graphiqlKoa({endpointURL: '/graphql'})(ctx, next)
})
module.exports = ticketRouter;
还有之前定义的user.router.ts(测试这个user路由是否是reachable的):
const Router = require('koa-router');
const userRouter = new Router();
// @ts-ignore
const { graphiqlKoa } = require('graphql-server-koa');
userRouter.get('/user/all', async (ctx) => {
ctx.body = {
code: '0',
msg: 'OK',
info: {
data: [{
username: 'a',
id: 0,
desc: 'ok',
}, {
username: 'd',
id: 1,
desc: 'ok',
}, {
username: 'c',
id: 2,
desc: 'ok',
}, {
username: 'b',
id: 3,
desc: 'ok',
}]
}
}
});
module.exports = userRouter;
将两个路由文件融合起来(combineRouter.ts):
const UserRouter:object = require('./koa-router/user.router');
const TicketRouter:object = require('./koa-router/ticket.router');
const combiler = (routers: object[]): object => {
let arr = [];
routers.forEach(v => {
//@ts-ignore
arr.push(...v.stack)
});
return Object.assign(routers[0], { stack:arr });
}
const res = combiler([UserRouter, TicketRouter]);
module.exports = res;
OK了,这部分就写好了基础的query和mutation功能,还有删除的功能之后再加上。
附上tsconfig.json文件:
{
"compilerOptions": {
"module": "commonjs",
"target": "es6",
"sourceMap": true,
"experimentalDecorators": true,
},
"exclude": [
"node_modules"
]
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。